package com.example.mq.mqserver.core;

import com.example.mq.common.MqException;

/**
 * 交换机的转发规则
 * 验证 bindingKey 是否合法
 */
public class Router {
    public boolean checkBindingKey(String bindingKey) {
        if (bindingKey.length() == 0) {
            //DIRECT的情况下
            return true;
        }

        for (int i = 0; i < bindingKey.length(); i++) {
            Character ch = bindingKey.charAt(i);
            if (ch >= 'A' && ch <= 'Z') {
                continue;
            }
            if (ch >= '0' && ch <= '9') {
                continue;
            }
            if (ch >= 'a' && ch <= 'z') {
                continue;
            }
            if (ch == '_' || ch == '.' || ch == '#' || ch == '*') {
                continue;
            }

            return false;
        }

        // 检查 * 或者 # 是否是独立的部分.
        String[] words = bindingKey.split("\\.");
        for (String word : words) {
            // 检查 word 长度 > 1 并且包含了 * 或者 # , 就是非法的格式了.
            if (word.length() > 1 && (word.contains("*") || word.contains("#"))) {
                return false;
            }
        }
        // 1. aaa.#.#.bbb    => 非法
        // 2. aaa.#.*.bbb    => 非法
        // 3. aaa.*.#.bbb    => 非法
        // 4. aaa.*.*.bbb    => 合法
        for (int i = 0; i < words.length - 1; i++) {
            // 连续两个 ##
            if (words[i].equals("#") && words[i + 1].equals("#")) {
                return false;
            }
            // # 连着 *
            if (words[i].equals("#") && words[i + 1].equals("*")) {
                return false;
            }
            // * 连着 #
            if (words[i].equals("*") && words[i + 1].equals("#")) {
                return false;
            }
        }
        return true;
    }


    public boolean checkRoutingKey(String routingKey) {
        //routingKey的规则
        //由 字母 下划线 和 . 组成的
        if (routingKey.length() == 0) {
            //routingKey 为空是合法的 FANOUT交换机不需要绑定路由就可以将消息发送到所有队列
            return true;
        }

        for (int i = 0; i < routingKey.length(); i++) {
            Character ch = routingKey.charAt(i);
            if (ch >= 'A' && ch <= 'Z') {
                continue;
            }
            if (ch >= '0' && ch <= '9') {
                continue;
            }
            if (ch == '_' || ch == '.') {
                continue;
            }
            if (ch >= 'a' && ch <= 'z') {
                continue;
            }
            return false;

        }
        return true;
    }

    //校验这个类型的交换机能否发送消息
    public boolean route(ExchangeType exchangeType, Binding binding, Message message) throws MqException {
        if (exchangeType == ExchangeType.FANOUT) {
            return true;
        } else if (exchangeType == ExchangeType.TOPIC) {
            return routeTopic(binding, message);
        } else {
            throw new MqException("[VirtualHost]交换机类型错误！");
        }
    }



    public boolean routeTopic(Binding binding, Message message) {
        //将两个key进行按.划分开
        String[] bindingTokens = binding.getBindingKey().split("\\.");
        String[] routingTokens = message.getRoutingKey().split("\\.");

        int bindingIndex = 0;
        int routingIndex = 0;

        while (bindingIndex < bindingTokens.length && routingIndex < routingTokens.length) {
            //遇到 * 不需要对比 两者下标++
            if (bindingTokens[bindingIndex].equals("*")) {
                bindingIndex++;
                routingIndex++;

            } else if (bindingTokens[bindingIndex].equals("#")) {
                //判断#后还有没有值
                bindingIndex++;
                if (bindingIndex == bindingTokens.length) {
                    //#后面没有值了
                    return true;
                }
                //还有值则找到routingKey的位置
                routingIndex = findNextMatch(routingTokens, routingIndex, bindingTokens[bindingIndex]);
                if (routingIndex == -1) {
                    return false;
                }
                bindingIndex++;
                routingIndex++;
            } else {
                //普通情况 看两是边否相等
                if (!bindingTokens[bindingIndex].equals(routingTokens[routingIndex])) {
                    return false;
                }
                bindingIndex++;
                routingIndex++;

            }
        }
        //判断两者是否同时到达尾部 不同时则不匹配
        if (bindingIndex == bindingTokens.length && routingIndex == routingTokens.length) {
            return true;
        }
        return false;
    }


    private int findNextMatch(String[] routingTokens, int routingIndex, String bindingToken) {
        for (int i = routingIndex; i < routingTokens.length; i++) {
            if (routingTokens[i].equals(bindingToken)) {
                return i;
            }
        }
        return -1;
    }


}
